package com.doge.calcalbum.business.update

import android.annotation.SuppressLint
import android.content.DialogInterface
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.view.*
import com.doge.calcalbum.core.BaseDialogFragment
import com.doge.calcalbum.databinding.DialogFragmentUpdateAppVersionBinding
import com.doge.calcalbum.utils.*
import java.io.File

@SuppressLint("QueryPermissionsNeeded")
class UpdateAppVersionDialogFragment : BaseDialogFragment() {
    private var innerBinding: DialogFragmentUpdateAppVersionBinding? = null
    private val binding get() = innerBinding!!
    private val versionNo by lazy { arguments?.getInt(EXTRA_VERSION_NO)!! }
    private val versionMinNo by lazy { arguments?.getInt(EXTRA_VERSION_MIN_NO)!! }
    private val versionDesc by lazy { arguments?.getString(EXTRA_VERSION_DESC)!! }
    private val versionUrl by lazy { arguments?.getString(EXTRA_VERSION_URL)!! }
    override val hasShadow = true
    private val appUpdateDir by lazy {
        File(activity?.externalCacheDir?.parent, "files/update").apply {
            if (!exists() || !isDirectory) {
                delete()
                mkdirs()
            }
        }
    }
    private val hasInstallPermission: Boolean
        get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
            appContext.packageManager.canRequestPackageInstalls() else false

    private var downingProgress: Int = 0
    private var forceUpdate: Boolean = false
    private var downloadTimes: Int = 0
    private var isDownloading: Boolean = false // 是否下载
    private var isDownloaded = false

    override fun setWindow(win: Window) {
        super.setWindow(win)
        win.setGravity(Gravity.CENTER)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        innerBinding = innerBinding
            ?: DialogFragmentUpdateAppVersionBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        dialog?.setCanceledOnTouchOutside(false)
        dialog?.setOnKeyListener(onBackListener)
        if ((versionMinNo) > appVersionCode) {
            forceUpdate = true // 需要强更
            binding.cancel.visibility = View.GONE
            binding.line2.visibility = View.GONE
        } else {
            forceUpdate = false
            binding.cancel.visibility = View.VISIBLE
            binding.line2.visibility = View.VISIBLE
        }
        binding.descText.text = versionDesc
        binding.cancel.setOnClickCallback {
            dismissAllowingStateLoss()
        }
        binding.confirm.setOnClickCallback {
            processInstall()
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        binding.cancel.setOnClickListener(null)
        binding.confirm.setOnClickListener(null)
        dialog?.setCanceledOnTouchOutside(false)
        innerBinding = null
    }

    private fun getFileName(url: String): String {
        val index = url.lastIndexOf("/")
        return if (index < 0) url.hashCode().toString() else url.substring(index + 1)
    }

    private fun processInstall() {
        File(appUpdateDir, getFileName(versionUrl)).also {
            if (it.exists()) {
                //如果文件存在并且当前已经下载的版本号小于服务器要求更新的版本，继续下载最新安装包
                val versionCode = apkInfo(it.absolutePath)
                if (versionCode == -1) return
                if (versionCode < versionNo) { //先删除旧的、下载最新的
                    log("AppUpdate processInstall download $versionCode $versionNo")
                    download(it)
                } else {
                    log("AppUpdate processInstall installAPK $versionCode $versionNo")
                    installAPK(it)
                }
            } else {
                log("AppUpdate processInstall download")
                download(it)
            }
        }
    }

    private fun download(file: File) {
        log("AppUpdate download to $file")
        binding.progressBar.visibility = View.VISIBLE
        binding.progressBar.setMaxProgress(100)
        binding.progressBar.setBgColor(getColor("#FFF6F6"))
        binding.progressBar.setProgressColor(getColor("#FF5F5F"))

        DownloadUtil.download(versionUrl, file) { status, downLoadSize, totalSize ->
            runOnUI {
                if (activity != null && activity?.isFinishing != true && activity?.isDestroyed != true) {
                    when (status) {
                        DownloadUtil.Status.DOWNLOAD_SUCCESS -> {
                            downingProgress = 0
                            isDownloading = false
                            binding.cancel.isEnabled = true
                            binding.confirm.isEnabled = true
                            binding.progressBar.visibility = View.GONE
                            isDownloaded = true
                            installAPK(file)
                        }
                        DownloadUtil.Status.DOWNLOADING -> {
                            binding.cancel.isEnabled = false
                            binding.confirm.isEnabled = false
                            downingProgress += downLoadSize
                            val percent = downLoadSize.toFloat() / totalSize * 100
                            binding.progressBar.progress = percent.toInt()
                            isDownloading = true
                        }
                        DownloadUtil.Status.DOWNLOAD_FAILED -> {
                            downloadTimes++
                            toast("下载安装包文件失败")
                            downingProgress = 0
                            isDownloading = false
                            binding.cancel.isEnabled = true
                            binding.confirm.isEnabled = true
                            binding.progressBar.visibility = View.GONE
                            if (downloadTimes >= 3) {
                                //三次下载失败，直接跳转浏览器下载
                                openBrowser()
                            }
                        }
                        else -> {
                        }
                    }
                }
            }
        }
    }

    private fun installAPK(apkFile: File) {
        val context = activity ?: return
        val intent = Intent(Intent.ACTION_VIEW)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.flags =
                Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK
            val contentUri: Uri = ApiCompat.getUri(apkFile)
            intent.setDataAndType(contentUri, "application/vnd.android.package-archive")
        } else {
            intent.setDataAndType(
                Uri.fromFile(apkFile),
                "application/vnd.android.package-archive"
            )
            intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
        }
        if (context.packageManager.queryIntentActivities(intent, 0).size > 0) {
            try {
                log("AppUpdate installAPK")
                context.startActivity(intent)
            } catch (ignore: Throwable) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    if (!hasInstallPermission) {
                        log("AppUpdate installAPK to require install permission")
                        startInstallPermissionSettingActivity {}
                    } else {
                        openBrowser() // 不知道啥原因失败了.浏览器兜底
                    }
                }
            }
        } else {
            openBrowser()
        }
    }


    private fun openBrowser() {
        val context = activity ?: return
        log("AppUpdate openBrowser")
        val intent = Intent()
        intent.action = Intent.ACTION_VIEW
        intent.data = Uri.parse(versionUrl)//直接打开浏览器下载apk
        if (intent.resolveActivity(context.packageManager) != null) {
            context.startActivity(Intent.createChooser(intent, "请选择浏览器"))
        } else {
            toast("链接错误或无浏览器")
        }
    }

    private fun apkInfo(absPath: String): Int {
        val context = activity ?: return -1
        val pm: PackageManager = context.packageManager
        val pkgInfo = pm.getPackageArchiveInfo(absPath, PackageManager.GET_ACTIVITIES)
        if (pkgInfo != null) {
            val appInfo = pkgInfo.applicationInfo
            appInfo.sourceDir = absPath
            appInfo.publicSourceDir = absPath
            val appName = pm.getApplicationLabel(appInfo).toString() // 得到应用名
            val packageName = appInfo.packageName // 得到包名
            val version = pkgInfo.versionName // 得到版本信息
            val versionCode = pkgInfo.versionCode
            log("AppUpdate update info $appName,$packageName,$version,$versionCode")
            return versionCode
        }
        return -1
    }

    private val onBackListener = object : DialogInterface.OnKeyListener {
        override fun onKey(p0: DialogInterface?, p1: Int, p2: KeyEvent?): Boolean {
            if (p1 == KeyEvent.KEYCODE_BACK) {
                if (forceUpdate) return true
                if (isDownloading) return true
            }
            return false
        }
    }

    companion object {
        private const val EXTRA_VERSION_NO = "update_version_no"
        private const val EXTRA_VERSION_MIN_NO = "update_version_min_no"
        private const val EXTRA_VERSION_DESC = "update_version_desc"
        private const val EXTRA_VERSION_TITLE = "update_version_title"
        private const val EXTRA_VERSION_URL = "update_version_url"

        fun newInstance(
            versionNo: Int,
            versionMinNo: Int,
            versionDesc: String?,
            versionTitle: String?,
            versionUrl: String
        ): UpdateAppVersionDialogFragment {
            return UpdateAppVersionDialogFragment().apply {
                arguments = Bundle().apply {
                    putInt(EXTRA_VERSION_NO, versionNo)
                    putInt(EXTRA_VERSION_MIN_NO, versionMinNo)
                    putString(EXTRA_VERSION_DESC, versionDesc)
                    putString(EXTRA_VERSION_TITLE, versionTitle)
                    putString(EXTRA_VERSION_URL, versionUrl)
                }
            }
        }
    }

}